home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 February: Technology Seed / Mac Tech Seed Feb '97.toast / OpenDoc 1.2b2c1 / Implementation / Memory / MemMgrM.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1997-02-13  |  13.6 KB  |  522 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        MemMgrM.cpp
  3.  
  4.     Contains:    Mac-specific implementations of MemMgr calls
  5.  
  6.     Owned by:    Jens Alfke
  7.  
  8.     Copyright:    © 1994 - 1997 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     Change History (most recent first):
  11.     
  12.          <5>      1/8/97    DH        1401434: Properly handle low mem for
  13.                                     MMSetHandleSize; remove redunant low-mem
  14.                                     check in MMCopyHandle; check for low-mem
  15.                                     after handle allocations in the app heap.
  16.          <4>    27.09.1996    NP        1386083: New routines and changes to
  17.                                     MMSetHandleSize and MMAllocateHnadleIn
  18.          <3>     9/19/96    DH        Task: low memory changes,1377922,1377888.
  19.                                     MMSystemFreeSpace now returns true
  20.                                     number.OutOfAvailMem checks for out of free
  21.                                     mem and tracks low mem.
  22.          <2>     9/13/96    jpa        115386: Optimize MMSystemFreeSpace by
  23.                                     caching a temp handle.
  24.         <10>    10/24/95    jpa        1293441: Added slush-fund. Allocate
  25.                                     temp-mem handles out of app heap if
  26.                                     absolutely necessary.
  27.          <9>     10/4/95    jpa        MMCopyHandle allocates in current heap's
  28.                                     area. [1289074]
  29.          <8>      5/5/95    TJ        jpa: ApplicZone --> ApplicationZone.
  30.          <7>      5/4/95    jpa        Added free-space fns, and maintain a
  31.                                     certain minimum free space in handle
  32.                                     allocation ops [1235657]
  33.          <6>     1/25/95    jpa        Removed HandToHand workaround now that
  34.                                     we're on Dagon a2. [1209733]
  35.          <5>     1/12/95    jpa        Took out five-dollar-sign mark and added
  36.                                     Radar bug 1209733. [1210981]
  37.          <4>     12/5/94    jpa        Nuked errant pragma lib_export's. [1195676]
  38.          <3>    10/12/94    JA        Added 68k workaround for HandToHand; no
  39.                                     effect on PPC build.
  40.          <2>     9/29/94    RA        1189812: Mods for 68K build.
  41.          <1>     9/14/94    jpa        first checked in
  42.  
  43.     To Do:
  44.     In Progress:
  45.         
  46. */
  47.  
  48.  
  49. #ifndef _MEMMGR_
  50. #include "MemMgr.h"
  51. #endif
  52.  
  53. #ifndef _MEMMGRPV_
  54. #include "MemMgrPv.h"
  55. #endif
  56.  
  57. #ifndef _MEMDEBG_
  58. #include "MemDebg.h"
  59. #endif
  60.  
  61. #ifndef __MEMORY__
  62. #include <Memory.h>        // Mac memory manager
  63. #endif
  64.  
  65. #ifndef __ERRORS__
  66. #include <Errors.h>
  67. #endif
  68.  
  69.  
  70. const size_t kMaxHandleBlockSize = 0x7FFFFFFF;
  71.  
  72. #if MM_DEBUG
  73. const size_t kTempMemFudge = 1000*1024;
  74. #else
  75. const size_t kTempMemFudge =  100*1024;
  76. #endif
  77.  
  78.  
  79. size_t gHandleMemFullMark = 0; // 0 means no mark.
  80.  
  81.  
  82.  
  83. static void MMSystemFreeSpace( Zone *zone, size_t *total, size_t *contig );
  84. static size_t GetFreeTempMemAndAppMem();
  85.  
  86.  
  87. static mmboolean
  88. FreeSpaceLow( MMHandle h )
  89. {
  90.     if( !h )
  91.         return kMMFalse;
  92.     Zone *zone = ::HandleZone((Handle)h);
  93.     if( MemError() )
  94.         return kMMTrue;
  95.     size_t free,contig;
  96.     MMSystemFreeSpace(zone,&free,&contig);
  97.     return (free < kPlatformMinFreeSpace || contig < kPlatformMinContigSpace);
  98. }
  99.  
  100. static MMBoolean OutOfAvailableMemoryForHandle( MMHandle h, size_t size )
  101. {
  102.     // This function returns a boolean that signifies, given the block
  103.     // we have allocated, whether we are now out of free memory. We have to do 
  104.     // an after the fact check because temp mem cannot be reliably checked before
  105.     // allocation (i.e. another allocation may have already taken place in the
  106.     // time after we decided that we had enough free memory, and the actual allocation
  107.     // takes place, etc.)
  108.     
  109.     if( !h )
  110.         return kMMFalse;
  111.     Zone *zone = ::HandleZone((Handle)h);
  112.     if( MemError() )
  113.         return kMMTrue;
  114.     size_t free,contig;
  115.     MMSystemFreeSpace(zone,&free,&contig);
  116.  
  117.     // In the system there are two points of low memory. 
  118.     //    1. Out of memory threshold.
  119.     //        • Once this amount of total/contig free space is reached, no more allocations
  120.     //        will be honored.
  121.     //    2. Low space threshhold.
  122.     //        • When memory is under this threshold, only allocations that don't take
  123.     //        up the rest of free space wiill succeed. The size of the block that will
  124.     //        succeed is based upon what percentage of the free space it will take up.
  125.     if( free < kPlatformMinFreeSpace || contig < kPlatformMinContigSpace )
  126.         return kMMFalse;
  127.     if( free < kPlatformLowTotalSpace || contig < kPlatformLowContigSpace )
  128.         if ( size/free < kMinFreeRatio )
  129.             return kMMTrue;
  130.     return kMMFalse;
  131. }
  132.  
  133. static Zone*
  134. TempMemZone( )
  135. {
  136.     // The only reliable way to get the Process Manager (temp-mem) zone is to call
  137.     // HandleZone on a temp handle. To avoid the overhead of allocating a handle
  138.     // every time, keep a tiny one around as a static variable.
  139.     
  140.     static Handle sTempMemHandle = NULL;
  141.     
  142.     if( !sTempMemHandle ) {
  143.         OSErr err;
  144.         sTempMemHandle = ::TempNewHandle(0,&err);
  145.         if( err ) {
  146.             MM_WARN("Eek, couldn't allocate hdl to find temp-mem zone!");
  147.             return kMMNULL;
  148.         }
  149.     }
  150.     return ::HandleZone(sTempMemHandle);
  151. }
  152.  
  153.  
  154. //========================================================================================
  155. // OPERATIONS ON RELOCATABLE BLOCKS (HANDLES)
  156. //========================================================================================
  157.  
  158.  
  159. //----------------------------------------------------------------------------------------
  160. // MMAllocateHandle
  161. //----------------------------------------------------------------------------------------
  162.  
  163. MMHandle MMAllocateHandle(size_t howBig)
  164. {
  165.     return MMAllocateHandleIn(howBig,gDefaultHeap->GetLocation());
  166. }
  167.  
  168. //----------------------------------------------------------------------------------------
  169. // MMAllocateHandleIn
  170. //----------------------------------------------------------------------------------------
  171.  
  172. MMHandle MMAllocateHandleIn(size_t size, MMHeapLocation loc)
  173. {
  174. #if MM_DEBUG
  175.     if (GetFreeTempMemAndAppMem() + size < gHandleMemFullMark)
  176.         return 0;
  177. #endif
  178.  
  179. #if MMDebug
  180.     if( size>kMaxHandleBlockSize ) {
  181.         MM_WARN("Bogus size 0x%08lx for MMAllocateHandle",size);
  182.         return kMMNULL;
  183.     }
  184. #endif
  185.  
  186.     Handle handle;
  187.     OSErr err;
  188.     
  189.     switch( loc ) {
  190.         case kMMSysMemory:
  191.             handle = ::NewHandleSys(size);
  192.             err = MemError();
  193.             break;
  194.         case kMMAppMemory:
  195.             SetZone(ApplicationZone());
  196.             handle = ::NewHandle(size);
  197.             err = MemError();
  198.             break;
  199.         case kMMTempMemory:
  200.             handle = ::TempNewHandle(size, &err);
  201.             break;
  202.         default:
  203.             MM_WARN("MMAllocateHandleIn: Bogus memory source!");
  204.             return 0;
  205.     }
  206.     
  207.     if( err!=noErr && err!=memFullErr )
  208.         MM_WARN("MMAllocateHandle got err %d",err);
  209.     
  210.     if (OutOfAvailableMemoryForHandle( handle, size ) )
  211.     {
  212.         MMFreeHandle(handle);
  213.         handle = kMMNULL;
  214.     }
  215.  
  216.     if( handle == kMMNULL && loc==kMMTempMemory ) {
  217.         // Allow temp-mem handle to be allocated out of app heap if there's room.
  218.         // It's easy for temp-mem to become totally wedged (just launch an app whose
  219.         // "preferred size" is greater than the amount available), which would
  220.         // otherwise totally prevent allocation of handles.
  221.         handle = (Handle) MMAllocateHandleIn(size,kMMAppMemory);
  222.         if (OutOfAvailableMemoryForHandle( handle, size ) )
  223.         {
  224.             MMFreeHandle(handle);
  225.             handle = kMMNULL;
  226.         }
  227.     }
  228.     
  229. #if MMDebug
  230.     if( gValidate>0 && handle )
  231.         Zap(*(Handle)handle, size, 0xBBBBBBBB);
  232. #endif
  233.  
  234.     return (MMHandle) handle;
  235. }
  236.  
  237. //----------------------------------------------------------------------------------------
  238. // MMFreeHandle
  239. //----------------------------------------------------------------------------------------
  240.  
  241. void MMFreeHandle(MMHandle handle)
  242. {
  243.     if( handle != kMMNULL ) {
  244. #if MMDebug
  245.         if( gValidate>0 ) {
  246.             if( !MMValidateHandle(handle) )
  247.                 return;
  248.             Zap(*(Handle)handle, GetHandleSize((Handle)handle), 0xDD);
  249.         }
  250.         
  251.         if( HGetState((Handle)handle) & 0x20 ) {
  252.             MM_WARN("MMFreeHandle: Tried to dispose rsrc %p",handle);
  253.             return;
  254.         }
  255. #endif
  256.         
  257.         DisposeHandle((Handle)handle);
  258.         
  259. #if MMDebug
  260.         OSErr err = MemError();
  261.         if( err!=noErr )
  262.             MM_WARN("MMFreeHandle: DisposeHandle returned err %d",err);
  263. #endif
  264.     }
  265. }
  266.  
  267. //----------------------------------------------------------------------------------------
  268. // MMCopyHandle
  269. //----------------------------------------------------------------------------------------
  270.  
  271. MMHandle MMCopyHandle( MMHandle handle )
  272. {
  273.     if( handle == kMMNULL ) {
  274.         MM_WARN("MMCopyHandle(NULL)!");
  275.         return kMMNULL;
  276.     }
  277.  
  278. #if MMDebug
  279.     if( gValidate>0 )
  280.         if( !MMValidateHandle(handle) )
  281.             return kMMNULL;
  282.     if( (HGetState((Handle)handle)&0x20) && !(HGetState((Handle)handle)&0x80) )
  283.         MM_WARN("Copying purgeable handle %p",handle);
  284. #endif
  285.  
  286.     size_t size = GetHandleSize((Handle) handle);
  287.     if( MemError() ) {
  288.         MM_WARN("MMCopyHandle got err %d",MemError());
  289.         return kMMNULL;
  290.     }
  291.     
  292.     MMHandle copy = MMAllocateHandle(size);
  293.     if( copy )
  294.         PlatformCopyMemory(*(Handle)handle,*(Handle)copy,size);
  295.  
  296.     return copy;
  297. }
  298.  
  299. //----------------------------------------------------------------------------------------
  300. // MMGetHandleSize(MMHandle handle)
  301. //----------------------------------------------------------------------------------------
  302.  
  303. size_t MMGetHandleSize(MMHandle handle)
  304. {
  305.     size_t    blkSize;
  306.     
  307. #if MMDebug
  308.     if( gValidate>0 )
  309.         if( !MMValidateHandle(handle) )
  310.             return 0;
  311. #endif
  312.         
  313.     blkSize = GetHandleSize((Handle) handle);
  314.     if( MemError() ) {
  315.         MM_WARN("MMGetHandleSize got err %d",MemError());
  316.         blkSize = 0;
  317.     }
  318.     return blkSize;
  319. }
  320.  
  321. //----------------------------------------------------------------------------------------
  322. // MMSetHandleSize(MMHandle handle, size_t blkSize)
  323. //----------------------------------------------------------------------------------------
  324.  
  325. MMBoolean MMSetHandleSize(MMHandle handle, size_t blkSize)
  326. {
  327.     size_t oldSize = ::GetHandleSize((Handle)handle);
  328.     
  329.     if( blkSize == oldSize )
  330.         return kMMTrue;
  331.  
  332. #if MM_DEBUG
  333.     size_t    freePlatformMem = GetFreeTempMemAndAppMem();
  334.     if (freePlatformMem - (blkSize - oldSize) < gHandleMemFullMark)
  335.         return 0;
  336. #endif
  337.  
  338. #if MMDebug
  339.     if( blkSize>kMaxHandleBlockSize ) {
  340.         MM_WARN("Bogus blkSize %08lx for MMSetHandleSize",blkSize);
  341.         return kMMFalse;
  342.     }
  343.     if( gValidate>0 ) {
  344.         if( !MMValidateHandle(handle) )
  345.             return kMMFalse;
  346.         // If block will shrink, zap area that will be lost:
  347.         if( blkSize < oldSize )
  348.             memset(OFFSET(*(Handle)handle,blkSize), 0xDD, oldSize-blkSize);
  349.     }
  350. #endif
  351.     
  352.     SetHandleSize((Handle) handle, blkSize);
  353.     OSErr err = MemError();
  354.     if( err ) {
  355.         if( err!=memFullErr )
  356.             MM_WARN("MMSetHandleSize got err %d",err);
  357.         return kMMFalse;
  358.     }
  359.     
  360.     if( blkSize>oldSize && OutOfAvailableMemoryForHandle(handle,blkSize) ) {
  361.         ::SetHandleSize((Handle)handle,oldSize);        // Back out the change
  362.         return kMMFalse;
  363.     }
  364.  
  365. #if MMDebug
  366.     // If block grew, zap new space at end:
  367.     if( gValidate>0 )
  368.         if( blkSize > oldSize )
  369.             memset(OFFSET(*(Handle)handle,oldSize),0xBB,(size_t)(blkSize-oldSize));    // Fill new space with BB
  370. #endif
  371.  
  372.     return kMMTrue;
  373. }
  374.  
  375. //----------------------------------------------------------------------------------------
  376. // MMLockHandle(MMHandle handle)
  377. //----------------------------------------------------------------------------------------
  378.  
  379. void* MMLockHandle(MMHandle handle)
  380. {
  381. #if MMDebug
  382.     if( gValidate>0 )
  383.         if( !MMValidateHandle(handle) )
  384.             return kODNULL;
  385. #endif
  386.         
  387.     HLock((Handle) handle);
  388.     OSErr err = MemError();
  389.     if( err ) {
  390.         MM_WARN("MMLockHandle got err %d",err);
  391.         return kMMNULL;
  392.     }
  393.     
  394.     return *(Handle) handle;
  395. }
  396.  
  397. //----------------------------------------------------------------------------------------
  398. // MMUnlockPtr(void* ptr)
  399. //----------------------------------------------------------------------------------------
  400.  
  401. void MMUnlockPtr(void* ptr)
  402. {
  403.     if( ptr==kMMNULL ) {
  404.         MM_WARN("MMUnlockPtr(NULL)!");
  405.     } else {
  406.         MMHandle handle = (MMHandle) RecoverHandle((Ptr) ptr);
  407.         if( MemError() )
  408.             MM_WARN("MMUnlockPtr(%p) got err %d",ptr,MemError());
  409.         else if (handle != kMMNULL) {
  410. #if MMDebug
  411.             if( HGetState((Handle)handle) & 0x80) )
  412.                 MM_WARN("MMUnlockPtr(%p): Hdl %p already unlocked",ptr,h);
  413. #endif
  414.             HUnlock((Handle) handle);
  415.         }
  416.     }
  417. }
  418.  
  419. //----------------------------------------------------------------------------------------
  420. // MMUnlockHandle(MMHandle handle)
  421. //----------------------------------------------------------------------------------------
  422.  
  423. void MMUnlockHandle(MMHandle handle)
  424. {
  425. #if MMDebug
  426.     if( gValidate>0 )
  427.         if( !MMValidateHandle(handle) )
  428.             THROW(kMMErrMemoryProblem);
  429. #endif
  430.         
  431.     HUnlock((Handle) handle);
  432.     if( MemError() )
  433.         MM_WARN("MMUnlockHandle(%p) got err %d",handle,MemError());
  434. }
  435.  
  436.  
  437. //----------------------------------------------------------------------------------------
  438. // MMSystemFreeSpace
  439. //----------------------------------------------------------------------------------------
  440.  
  441. void MMSystemFreeSpace( MMHeapLocation loc, size_t *total, size_t *contig )
  442. {
  443.     size_t tempTotal, tempContig;
  444.     if( !total ) total = &tempTotal;
  445.     if( !contig) contig= &tempContig;
  446.     
  447.     Zone *zone = kMMNULL;
  448.     
  449.     switch( loc ) {
  450.         case kMMSysMemory:
  451.             zone = SystemZone();
  452.             break;
  453.             
  454.         case kMMAppMemory:
  455.             zone = ApplicationZone();
  456.             break;
  457.             
  458.         case kMMTempMemory: {
  459.             zone = TempMemZone();
  460.             if( !zone ) { // no memory to find temp zone! must be full!
  461.                 *total = *contig = 0;
  462.                 return;
  463.             }
  464.         }
  465.     }
  466.     MMSystemFreeSpace(zone,total,contig);
  467. }
  468.  
  469.  
  470. static void MMSystemFreeSpace( Zone *zone, size_t *total, size_t *contig )
  471. {
  472.     if( zone ) {
  473.         Zone *curZone = GetZone();
  474.         SetZone(zone);
  475.         
  476.         *total = FreeMem();
  477.         *contig = MaxBlock();
  478.         size_t purgeTotal, purgeContig; 
  479.         PurgeSpace((long*)&purgeTotal,(long*)&purgeContig);
  480.         if( purgeTotal > *total )
  481.             *total = purgeTotal;
  482.         if( purgeContig > *contig )
  483.             *contig = purgeContig;
  484.         
  485.         SetZone(curZone);
  486.     } else
  487.         *total = *contig = 0;
  488. }
  489. #if MM_DEBUG
  490. //------------------------------------------------------------------------------
  491. // GetFreeTempMemAndAppMem
  492. //
  493. //    It seems that nobody is allocating handles in the system anymore, so I don't
  494. //    really handle that case here.
  495. //------------------------------------------------------------------------------
  496.  
  497. static size_t GetFreeTempMemAndAppMem()
  498. {
  499.     size_t    freeAppHeap;
  500.     size_t    freeTempMem;
  501.     size_t    ignore;
  502.  
  503.     MMSystemFreeSpace(ApplicationZone(), &freeAppHeap, &ignore);
  504.     MMSystemFreeSpace(TempMemZone(), &freeTempMem, &ignore);
  505.  
  506.     return freeAppHeap + freeTempMem;
  507. }
  508.  
  509. //------------------------------------------------------------------------------
  510. // MMSetHandleMemFullMark
  511. //------------------------------------------------------------------------------
  512.  
  513. void MMSetPlatformHandleMemFullMark()
  514. {
  515.     gHandleMemFullMark = GetFreeTempMemAndAppMem();
  516. }
  517.  
  518. void MMUnsetPlatformHandleMemFullMark()
  519. {
  520.     gHandleMemFullMark = 0;
  521. }
  522. #endif /* MM_DEBUG */